home *** CD-ROM | disk | FTP | other *** search
- /**************************************************************************\
- * *
- * *
- * ***** ***** *
- * ***** ***** *
- * ***** ***** *
- * ***** ***** *
- * ***** ***** *
- * ***** ***** *
- * ***** ***** *
- * ***** ***** The Firmware. The Net. *
- * ***** ***** Portable. Compatible. *
- * ***** ***** Public Domain. *
- * ***** ***** By NORD><LINK. *
- * *
- * *
- * *
- * L2C.C - Level 2, Teil 3 *
- * *
- * angelegt: DC4OX *
- * modifiziert: *
- * *
- * G8KBB April 1991 - use of register keywork to compress code *
- * condition include of cpyfb for KISS use *
- * Nov 1991 - accumulate stats on certain packets sent *
- * May 1993 - add non portable compare() function *
- * Add support for meters and additional alias handling *
- * *
- * September 1993 - released as TheNet X-1J *
- * *
- * add portflush support *
- * add various speedups *
- * *
- * Released as TheNet X-1J release 4, January 1995 *
- \**************************************************************************/
-
-
-
-
-
- /* Includes */
- /**************************************************************************/
-
- #include "all.h" /* allgemeine Festlegungen */
- #include "tntyp.h" /* Festlegungen/Datenstrukturen fuer den Level 2 */
- #include "l2s.h" /* Zugriff auf die State-Tabellen */
- #include "l2ext.h" /* globale Variable / nicht int-Funktionen */
-
-
-
-
-
- /**************************************************************************\
- * *
- * action : Zustandsuebergangsfunktionen der Level-2-Statetable *
- * (x.../t...), Level-2-Timer setzen/aufloesen (setT./clrT.) *
- * und Utilities fuer diese Funktionen. *
- * *
- * t2rrr() - Timer 2 setzen, nach Ablauf RR als Response zu senden *
- * t2rnrr() - Timer 2 setzen, nach Ablauf RNR als Response zu senden *
- * t2rejr() - Timer 2 setzen, nach Ablauf REJ als Response zu senden *
- * *
- * xnull() - nichts tun *
- * *
- * xrrc() - RR als Command senden *
- * xrrr() - RR als Response senden *
- * xrnrc() - RNR als Command senden *
- * xrnrr() - RNR als Response senden *
- * xrejr() - REJ als Response senden *
- * *
- * xdm() - DM senden *
- * xua() - UA senden *
- * xsabm() - SABM senden *
- * xdisc() - DISC senden *
- * *
- * xfrmr() - FRMR senden (-> L2E.C) *
- * *
- * setT1() - Timer 1 setzen und Timer 3 loeschen *
- * clrT1() - Timer 1 und tries loeschen, Timer 3 setzen *
- * setT2() - Timer 2 und nach Ablauf zu sendenden Frametyp setzen *
- * clrT2() - Timer 2 und nach Ablauf zu sendenden Frametyp loeschen *
- * setT3() - Timer 3 setzen, wenn Version 2 Protokoll benutzt wird *
- * clrT3() - Timer 3 loeschen *
- * *
- * sendS() - Supervisory-Frame fuer Sendung aufbauen, Timer 2 *
- * loeschen, Frame senden *
- * sdfrmr() - FRMR-Frame fuer Sendung aufbauen und senden (-> L2E.C) *
- * *
- \**************************************************************************/
-
- VOID t2rrr() { setT2(L2CRR); }
-
- VOID t2rnrr() { setT2(L2CRNR); }
-
- VOID t2rejr() { setT2(L2CREJ); }
-
- VOID setT1() { lnkpoi->T1 = lnkpoi->initT1 + random(); clrT3(); }
-
- VOID clrT1() { lnkpoi->T1 = lnkpoi->tries = 0; setT3(); }
-
- VOID setT2(Stype) char Stype;
- { lnkpoi->RStype = Stype; lnkpoi->T2 = T2par; }
-
- VOID clrT2() { lnkpoi->T2 = 0; lnkpoi->RStype = 0; }
-
- VOID setT3() { if (lnkpoi->V2link == YES) lnkpoi->T3 = T3par; }
-
- VOID clrT3() { lnkpoi->T3 = 0; }
-
- VOID xnull() { }
-
- VOID xrrc() { stxcfr(); xrrr(); }
-
- VOID xrrr() { sendS(L2CRR); }
-
- VOID xrnrc() { stxcfr(); xrnrr(); }
-
- VOID xrnrr() { sendS(L2CRNR);
- #ifdef STATSCMD
- L2TXRNR[lnkpoi->liport & MAXPORTMASK]++;
- #endif
- }
-
- VOID xrejr() { sendS(L2CREJ);
- #ifdef STATSCMD
- L2TXREJ[lnkpoi->liport & MAXPORTMASK]++;
- #endif
- }
-
- VOID sendS(control) char control;
- { clrT2(); txfctl=setNR(control);
- sdl2fr(makfhd(!txfCR ? L2FUS : (L2FUS | L2FT1ST))); }
-
- VOID xdm() { txfctl = L2CDM; sdl2fr(makfhd(L2FUS)); }
-
- VOID xua() { txfctl = L2CUA; sdl2fr(makfhd(L2FUS)); }
-
- VOID xsabm() { stxcfr(); txfctl = L2CSABM; sdl2fr(makfhd(L2FUS|L2FT1ST)); }
-
- VOID xdisc() { stxcfr(); txfctl = L2CDISC; sdl2fr(makfhd(L2FUS|L2FT1ST)); }
-
-
-
-
-
- /**************************************************************************\
- * *
- * "set tx command frame" *
- * *
- * TX-Frame-Adressierung setzen (siehe stxfad()) und Frame zum Kommando- *
- * frame machen mit gesetztem Pollbit (txfCR,txfPF). *
- * *
- \**************************************************************************/
-
- VOID stxcfr()
- {
- stxfad(); /* Adressierung */
- txfCR = L2CCR; /* Command ! */
- txfPF = L2CPF; /* Pollbit ! */
- }
-
-
-
-
-
- /**************************************************************************\
- * *
- * "set tx frame address" *
- * *
- * Adressierung des aktuellen Sendeframes (txfhdr, txfprt) setzen aus den *
- * im aktuellen Linkblock (lnkpoi) gegebenen Parametern (srcid, destid, *
- * viaidl, liport). *
- * *
- \**************************************************************************/
-
- VOID stxfad()
- {
- cpyid(txfhdr + L2IDLEN,lnkpoi->srcid); /* von ... */
- cpyid(txfhdr,lnkpoi->dstid); /* nach ... */
- cpyidl(txfhdr + L2ILEN,lnkpoi->viaidl); /* ueber ... */
- txfprt = lnkpoi->liport; /* auf Port ... */
- }
-
-
-
-
-
- /**************************************************************************\
- * *
- * "set NR" *
- * *
- * Im aktuellen Linkblock (lnkpoi) die zuletzt gesendete N(R) (ltxdNR) auf *
- * V(R) (VR) setzen und Framecontrolbyte control fuer Frameaussendung mit *
- * der N(R) versehen und zurueckgeben. *
- * *
- * Return : control mit N(R) versehen *
- * *
- \**************************************************************************/
-
- unsigned setNR(control)
-
- char control;
-
- {
- lnkpoi->ltxdNR = lnkpoi->VR; /* neue N(R) */
- return((lnkpoi->VR << 5) | control); /* N(R) ins Kontrollfeld */
- }
-
-
-
-
-
- /**************************************************************************\
- * *
- * "send level 2 frame" *
- * *
- * Framebuffer, auf dessen Kopf fbp zeigt, rewinden und in die dem Port *
- * (l2port) entsprechende Level-2-Sendeframeliste einhaengen, wenn noch *
- * genug Buffer im System frei sind. Andernfalls nicht senden, sondern *
- * sofort in die Gesendet-Liste (stfl) einhaengen. Bei TheNet die *
- * Sendeaktiviatetsvariable (istraf) des entsprechenden Ports setzen. *
- * *
- \**************************************************************************/
-
- VOID sdl2fr(fbp)
- register MBHEAD *fbp;
-
- {
- register unsigned port; /* Portnummer */
-
- port = fbp->l2port; /* Portnummer holen */
- if (nmbfre > 64) /* noch genug Buffer ? */
- {
- #ifdef STATSCMD
- L2TXCNT[port & MAXPORTMASK]++; /* bump tx count */
- #endif
- #ifdef PORTFLUSH
- pending[port] = 1;
- #endif
- rwndmb(fbp); /* ja - Framebuffer rewinden */
- DIinc(); /* Listenkonsistenz ! */
- relink(fbp,txl2fl[port].tail); /* Frame in Sendeliste */
- kicktx(port); /* es ist was zu senden ! */
- decEI(); /* Interrupts w. erlauben */
-
- #ifndef FIRMWARE
- istraf[port] = YES; /* es ist Port-Traffic */
- #endif
-
- }
- else /* nein - Frame einfach sofort */
- relink(fbp,stfl.tail); /* als gesendet betrachten */
- }
-
-
-
-
-
- /**************************************************************************\
- * *
- * "copy frame buffer" *
- * *
- * Framebuffer, auf den fbp zeigt, komplett mit Inhalt kopieren. Dazu freie *
- * Buffer allokieren, Portnummer (l1port) wird kopiert, Bufferzeiger (mbbp) *
- * und Getcounter (mbgc) werden nicht kopiert, bleiben aber im Quellframe *
- * erhalten. *
- * *
- * Return : Zeiger auf Kopf des kopierten Framebuffers *
- * *
- \**************************************************************************/
-
- /* #ifdef FIRMWARE */
- #ifdef INCLUDEcpyfb
-
- MBHEAD *cpyfb(fbp)
- register MBHEAD *fbp;
-
- {
- register char *savmbbp; /* mbbp-Sicherung */
- unsigned savmbgc; /* mbgc-Sicherung */
- register MBHEAD *newfbp; /* Zeiger auf die Kopie */
-
- savmbbp = fbp->mbbp; /* mbbp sichern */
- savmbgc = fbp->mbgc; /* mbgc sichern */
- rwndmb(fbp); /* Quellframe rewinden */
- newfbp = allocb(); /* Kopf der Kopie allokieren */
- #ifdef MODIFIED
- mhtyp_copy( fbp, newfbp );
- #else
- while (fbp->mbgc < fbp->mbpc) /* Daten byteweise kopieren */
- putchr(getchr(fbp),newfbp);
- #endif
- newfbp->l2port = fbp->l2port; /* Portnummer kopieren */
- fbp->mbbp = savmbbp; /* mbbp wieder auf alten Wert */
- fbp->mbgc = savmbgc; /* mbgc wieder auf alten Wert */
- return (newfbp); /* Zeiger auf Kopf der Kopie */
- }
-
- #endif
-
-
-
-
-
- /**************************************************************************\
- * *
- * "take frame head" *
- * *
- * Adresskopf und Kontrollbyte des Frames aus dem Framebuffer, auf dessen *
- * Kopf fbp zeigt, analysieren. Diese Funktion ist die erste, die auf ein *
- * empfangenes Frame angewandt wird. *
- * *
- * *
- * Folgende Parameter werden bei der Analyse gesetzt (siehe auch L2V.C) : *
- * *
- * rxfhdr, rxfV2, rxfPF, rxfCR, rxfctl, rxfprt *
- * *
- * *
- * Folgende Parameter werden nach der Analyse gesetzt fuer ein moegliches *
- * Antwortframe : *
- * *
- * txfhdr = Quell- und Zielcall aus rxfhdr, aber vertauscht, plus *
- * reverse via-Liste aus rxfhdr *
- * txfV2 = rxfV2 *
- * txfPF = rxfPF *
- * txfCR = 0, Response ! *
- * txfprt = rxfprt *
- * *
- * *
- * Return : TRUE - das Frame hat einen gueltigen AX.25-Framekopf *
- * FALSE - sonst *
- * *
- \**************************************************************************/
-
- BOOLEAN takfhd(fbp)
-
- MBHEAD *fbp;
-
- {
- register char *viap; /* Zeiger in via-Liste */
- register char *source; /* Quellzeiger Kopien */
- register char *dest; /* Zielzeiger Kopien */
-
- rwndmb(fbp); /* Frame von vorne */
- if ( !getfid(rxfhdr,fbp) /* Zielcall holen */
- || ((rxfhdr[L2IDLEN - 1] & L2CEOA) != 0) /* (Ende nach 1. Call ?)*/
- || !getfid(rxfhdr + L2IDLEN,fbp) /* Quellcall holen */
- ) return (FALSE); /* ... schon Fehler */
- viap = rxfhdr + L2ILEN; /* ab hier via-Liste */
- if (!(rxfhdr[L2ILEN - 1] & L2CEOA)) /* via-Liste da ? */
- LOOP
- { /* alle via's */
- if (!getfid(viap,fbp)) return (FALSE); /* Call holen */
- viap += L2IDLEN; /* naechstes Call */
- if ((*(viap - 1) & L2CEOA) != 0) break; /* Ende der Liste */
- if (viap >= rxfhdr + L2AFLEN) return (FALSE); /* zu lange Liste */
- }
- *viap = '\0'; /* Listenende ! */
- if (fbp->mbgc == fbp->mbpc) return (FALSE); /* Frame zu kurz */
- rxfctl = getchr(fbp); /* Controlbyte */
-
-
- /* Protokollversion feststellen und danach C/R und P/F festlegen */
-
- if ( (rxfV2 = ((rxfhdr[L2IDLEN - 1] ^ rxfhdr[L2ILEN - 1]) & L2CCR) != 0)
- == YES
- )
- { /* nur Version 2 : */
- rxfCR = rxfhdr[L2IDLEN - 1] & L2CCR; /* Command/Response */
- rxfPF = rxfctl & L2CPF; /* Poll/Final */
- }
- else /* Version 1 : */
- rxfPF = rxfCR = 0; /* P/F u. C/R sinnlos */
-
- rxfctl &= ~L2CPF; /* P/F Control loeschen */
- rxfprt = fbp->l2port; /* Portnummer holen */
-
- #ifdef METERS
- rxfdev = fbp->rxdev;
- siglev = fbp->sig_level;
- #endif
-
- /* Antwort-Sendeframeaufbau */
-
- txfCR = 0; /* Response ! */
- txfV2 = rxfV2; /* Version */
- txfPF = rxfPF; /* Poll/Final */
- txfprt = rxfprt; /* Portnummer */
- cpyid(txfhdr,rxfhdr + L2IDLEN); /* TX-Ziel = RX-Quelle */
- cpyid(txfhdr + L2IDLEN,rxfhdr); /* TX-Quelle = RX-Ziel */
- source = rxfhdr + L2ILEN; /* TX-Antwort-via-Liste */
- dest = txfhdr + L2ILEN; /* ist, falls vorhanden */
- {
- while (*source != '\0') source += L2IDLEN; /* reverse RX-via-Liste */
- while (source != rxfhdr + L2ILEN)
- {
- source -= L2IDLEN;
- cpyid(dest,source);
- dest += L2IDLEN;
- }
- }
- *dest = '\0'; /* Listenende ! */
- return (TRUE); /* Frame soweit okay ! */
- }
-
-
-
-
-
- /**************************************************************************\
- * *
- * "get frame ID" *
- * *
- * Die naechste ID nach dest (Call + SSID, SSID wie im Frame) holen aus dem *
- * Buffer (Call + SSID, beide wie im Frame), auf dessen Kopf mbhd zeigt. *
- * Die geholte SSID enthaelt das End-Of-Address-Bit unveraendert. *
- * *
- * Return : TRUE - die naechste ID (Call + SSID) wurde richtig geholt *
- * FALSE - es hat sich ein Fehler ereignet *
- * *
- \**************************************************************************/
-
- BOOLEAN getfid(dest,mb)
- char *dest;
- MBHEAD *mb;
- {
- register char c; /* aktuelles Zeichen aus Buffer */
- register unsigned n; /* Zaehler Call-Laenge */
- register MBHEAD *mbhd = mb;
-
- if (mbhd->mbpc - mbhd->mbgc < L2IDLEN) /* im Buffer nicht mehr */
- return (FALSE); /* genug Bytes fuer ID */
- for (n = L2CALEN; n != 0; --n) /* Call byteweise holen */
- {
- if (((c = getchr(mbhd)) & L2CEOA) != 0) /* Adressfeld zu frueh */
- return (FALSE); /* zuende */
- *dest++ = (c >> 1) & 0x7F; /* Framecall -> ASCII */
- }
- *dest = getchr(mbhd); /* SSID holen, EOA bleibt */
- return (TRUE);
- }
-
-
-
-
-
- /**************************************************************************\
- * *
- * "make frame head" *
- * *
- * Neues Frame aufbauen aus den txf...-Parametern. Es werden neue Buffer *
- * fuer das Frame allokiert, der aktuelle Linkblock (lnkpoi) wird *
- * eingetragen und fflag fuer das Frameflag l2fflg. *
- * *
- * Return : Zeiger auf Framebufferkopf des neu erzeugten Frames *
- * *
- \**************************************************************************/
-
- MBHEAD *makfhd(fflag)
-
- unsigned fflag;
-
- {
- register MBHEAD *fbp; /* Zeiger auf Kopf */
-
- if (txfV2 == YES) /* wenn Version 2 ... */
- {
- txfhdr[L2IDLEN - 1] |= txfCR; /* ... C-Bits setzen */
- txfhdr[L2ILEN - 1] |= txfCR ^ L2CCR;
- }
- putfid(txfhdr,fbp = allocb()); /* neuer Buffer, Ziel */
- putfid(txfhdr + L2IDLEN,fbp); /* Quellcall */
- putvia(txfhdr + L2ILEN,fbp); /* via-Liste */
- putchr(!txfV2 ? txfctl : txfctl | txfPF,fbp); /* Control + P/F */
- fbp->l2link = lnkpoi; /* Verweis Linkblock */
- fbp->type = 2; /* Level 2 ! */
- fbp->l2fflg = fflag; /* Frameflag */
- fbp->l2port = txfprt; /* Portnummer */
- return (fbp); /* Kopfzeiger zurueck */
- }
-
-
-
-
-
- /**************************************************************************\
- * *
- * "put via" *
- * *
- * Nullterminierte via-Liste, auf die idl zeigt, in den Framebuffer, auf *
- * dessen Kopf mbhd zeigt, uebertragen. Die Nullterminierung nicht ueber- *
- * tragen, aber am Ende der via-Liste das letzte Zeichen der via-Liste mit *
- * dem HDLC End-Of-Address-Bit uebertragen. *
- * *
- \**************************************************************************/
-
- VOID putvia(idl,mbhd)
- register char *idl;
- register MBHEAD *mbhd;
- {
- while (*idl != '\0') /* gesamte via-Liste in den */
- { /* Framebuffer uebertragen */
- putfid(idl,mbhd);
- idl += L2IDLEN;
- } /* dann */
- *(mbhd->mbbp - 1) |= L2CEOA; /* EoA direkt im Buffer setzen */
- }
-
-
-
-
-
- /**************************************************************************\
- * *
- * "put frame id" *
- * *
- * ID (Call und SSID, SSID wie im Frame), auf die id zeigt, in den *
- * Framebuffer, auf dessen Kopf mbhd zeigt, uebertragen. Dabei Call von *
- * ASCII in Frameformat (1 Bit linksgeschoben) umwandeln. *
- * *
- \**************************************************************************/
-
- VOID putfid(id,mbhd)
- register char *id;
- register MBHEAD *mbhd;
- {
- register unsigned n; /* Zaehler Call-Laenge */
-
- for (n = L2CALEN; n != 0; --n) /* Call uebertragen in Buffer, */
- putchr(*id++ << 1,mbhd); /* 1 Bit linksgeschoben */
- putchr(*id,mbhd); /* SSID unveraendert uebertragen */
- }
-
-
-
-
-
- /**************************************************************************\
- * *
- * "is to me" *
- * *
- * Pruefen, ob die ID (Call + SSID, SSID wie im Frame), auf die id zeigt, *
- * mit der ID der eigenen Station (myid) uebereinstimmt (SSID wird ohne *
- * Steuerbits verglichen), oder ob das Call, auf das id zeigt, mit dem *
- * symbolischen Namen (alias) der eigenen Station uebereinstimmt. *
- * *
- * Return : TRUE - myid stimmt mit id ueberein oder alias mit dem *
- * call in id *
- * FALSE - sonst *
- * *
- \**************************************************************************/
-
- BOOLEAN istome(id)
- register char *id;
-
- {
- return (cmpid(myid,id) || cmpcal(alias,id)
- #ifdef MODIFIED
- ||
- ( enaliases && ( cmpcal( bbsalias, id ) || cmpcal( hostalias, id )
- || cmpcal( dxcalias, id )))
- #endif
- );
- }
-
-
-
-
-
- /**************************************************************************\
- * *
- * "compare calls" *
- * *
- * Calls miteinander vergleichen. *
- * *
- * Return : TRUE - die Calls stimmen ueberein *
- * FALSE - die Calls stimmen nicht ueberein oder mindestens eins *
- * der Calls beginnt mit einem Blank *
- * *
- \**************************************************************************/
-
- #ifdef PORTABLE
- BOOLEAN cmpcal(call1,call2)
- register char *call1;
- register char *call2;
- {
- register unsigned n; /* Zaehler */
-
- if ( *call2 == ' ' || *call1 == ' ') /* 1. Zeich. ' ' ? */
- return( NO );
- #ifdef PORTABLE
- for (n = 0; n < L2CALEN; ++n) /* jedes Zeichen */
- if ( *call2++ != *call1++ ) /* sonst gleich ? */
- return (NO); /* nein */
- return (YES); /* ja, alle gleich */
- #else
- return( compare( call1, call2, L2CALEN ) );
- #endif
- }
- #endif
-
-
-
-
- /**************************************************************************\
- * *
- * "compare ID list" *
- * *
- * Nullterminierte ID-Listen (Calls + SSID's, SSID wie im Frame) *
- * miteinander vergleichen (SSID nur reine SSID 0-15 vergleichen ohne *
- * Steuerbits). *
- * *
- * Return : TRUE - die ID-Listen stimmen ueberein *
- * FALSE - sonst *
- * *
- \**************************************************************************/
-
- BOOLEAN cmpidl(idl1,idl2)
-
- register char *idl1;
- register char *idl2;
-
- {
- while (*idl2 != '\0') /* bis Liste 2 zuende */
- {
- if (!cmpid(idl1,idl2)) return (NO); /* ID's vergleichen */
- idl2 += L2IDLEN; /* Zeiger auf naechste */
- idl1 += L2IDLEN; /* ID's */
- } /* Listen gleich, wenn */
- return (!*idl1); /* beide zuende */
- }
-
-
-
-
-
- /**************************************************************************\
- * *
- * "compare ID's" *
- * *
- * ID's (Call + SSID, SSID wie im Frame) miteinander vergleichen (SSID nur *
- * reine SSID 0-15 vergleichen ohne Steuerbits). *
- * *
- * Return : TRUE - die ID's stimmen ueberein *
- * FALSE - sonst *
- * *
- \**************************************************************************/
-
- #ifdef PORTABLE
- BOOLEAN cmpid(id1,id2)
- register char *id1;
- register char *id2;
-
- {
- #ifdef PORTABLE
- register unsigned n; /* Zaehler */
-
- for (n = 0; n < L2CALEN; ++n) /* Calls vergleichen */
- if (*id2++ != *id1++) return (NO);
- return ((*id2 & 0x1E) == (*id1 & 0x1E)); /* reine SSID vergl. */
- #else
- if( !compare( id1, id2, L2CALEN ) )
- return( NO );
- return ((id2[L2CALEN] & 0x1E) == (id1[L2CALEN] & 0x1E)); /* reine SSID vergl. */
- #endif
- }
- #endif
-
-
-
-
- /**************************************************************************\
- * *
- * "copy ID list" *
- * *
- * Nullterminierte ID-Liste (Calls + SSID's, SSID wie im Frame) von source *
- * nach dest kopieren, Zielliste mit '\0' abschliessen. *
- * *
- \**************************************************************************/
-
- VOID cpyidl(dest,source)
- register char *dest;
- register char *source;
-
- {
- while (*source != '\0') /* solange Liste nicht zuende */
- {
- cpyid(dest,source); /* ID kopieren */
- source += L2IDLEN; /* Zeiger um eine ID-Laenge */
- dest += L2IDLEN; /* weiter */
- }
- *dest = '\0'; /* Zielliste abschliessen */
- }
-
-
-
-
-
- /**************************************************************************\
- * *
- * "copy ID" *
- * *
- * Komplette ID (Call + SSID, SSID wie im Frame), auf die source zeigt, *
- * nach dest kopieren. In der kopierten SSID das End-Of-Address-Bit und das *
- * Command/Response/Has-Been-Repeated-Bit loeschen. *
- * *
- \**************************************************************************/
-
- VOID cpyid(dest,source)
- register char *source;
- register char *dest;
-
- {
- #ifdef PORTABLE
- register unsigned n; /* Laengenzaehler */
-
- for (n = 0; n < L2CALEN; ++n) /* Call kopieren */
- *dest++ = *source++;
- *dest = *source & ~(L2CEOA | L2CCR); /* SSID kopieren, Bits loeschen */
- #else
- memcpy( dest, source, L2CALEN+1 );
- dest[L2CALEN] &= ~(L2CEOA | L2CCR); /* SSID kopieren, Bits loeschen */
- #endif
- }
-
-
-
-
-
- /**************************************************************************\
- * *
- * "deallocate message list" *
- * *
- * Komplette Messageliste, auf deren Listenkopf mlp zeigt, deallokieren. *
- * D.h. alle Messagespeicher (jeweils Kopf und daran haengende Datenbuffer) *
- * deallokieren. *
- * *
- * *
- * +--------+ +--------+ +--------+ *
- * mlp --->| head |--->| |---> --->| |---> mlp *
- * +--------+ +--------+ ... +--------+ *
- * b <---| tail |<---| |<--- <---| |<--- b *
- * +--------+ +--------+ +--------+ *
- * | |---> \ | |---> \ *
- * + + | + + | *
- * | |<--- /| | |<--- /| *
- * +--------+ | +--------+ | *
- * | | | | | | *
- * | | *
- * deallokieren |------------------------| *
- * siehe unten dealmb() *
- * *
- \**************************************************************************/
-
- VOID dealml(mlp)
- register LEHEAD *mlp;
-
- {
- register MBHEAD *bp; /* Zeiger auf Messagebufferhead */
-
- LOOP /* fuer alle Messagebufferheads */
- { /* in Messagespeicherliste : */
- DIinc(); /* Listenkonsistenz ! */
- bp = mlp->nextle; /* Zeiger auf naechsten Msgbhead */
- decEI(); /* Interrupts wieder erlauben */
- if (mlp == bp) break; /* Schwanz beisst Kopf -> fertig */
- dealmb(unlink(bp)); /* sonst Messagespeicher deallok. */
- }
- }
-
-
-
-
-
- /**************************************************************************\
- * *
- * "deallocate message buffer" *
- * *
- * Einen kompletten Messagespeicher, auf dessen Kopf mbhd zeigt, *
- * deallokieren, d.h. sowohl den Messagebufferhead als auch alle an dessen *
- * Messagebufferliste haengende Datenbuffer deallokieren. *
- * *
- * *
- * +--------+ deallokieren *
- * mbhd -->| | *
- * +--------+ *
- * | | *
- * +--------+ +--------+ +--------+ *
- * a --->| |----->| |---> --->| |---> a *
- * + mbl + +--------+ ... +--------+ *
- * b <---| |<-----| |<--- <---| |<--- b *
- * +--------+ +--------+ +--------+ *
- * | | | | | | *
- * *
- \**************************************************************************/
-
- VOID dealmb(mbhd)
- register MBHEAD *mbhd;
-
- {
- register MB *bp; /* Datenbufferzeiger */
-
- while ((bp = mbhd->mbl.head) != &mbhd->mbl) /* alle Datenbuffer */
- dealoc(unlink(bp));
- dealoc(mbhd); /* am Ende den Kopf */
- }
-
-
-
-
-
- /**************************************************************************\
- * *
- * "deallocate" *
- * *
- * Buffer, auf den bp zeigt, initialisieren als neuen Messagebufferhead *
- * (rwndmb()) und deallokieren, d.h. in die Freiliste freel einhaengen und *
- * den Freibufferzaehler nmbfre inkrementieren. *
- * *
- * *
- * +--------+ *
- * bp --->| | deallokieren *
- * +--------+ *
- * | | *
- * +--------+ *
- * | | *
- * *
- \**************************************************************************/
-
- VOID dealoc(bp)
- register MBHEAD *bp;
-
- {
- bp->mbl.head /* als Messagehead initialisieren */
- = bp->mbl.tail /* Bufferlistenkopf */
- = &bp->mbl; /* initialisieren */
- bp->mbpc = 0; /* Message leer */
- rwndmb(bp); /* Rest initialisieren */
- DIinc(); /* Listenkonsistenz ! */
- relink(bp,freel.tail); /* Buffer an Freiliste anhaengen */
- ++nmbfre; /* 1 Freibuffer mehr */
- decEI(); /* Interrupts wieder erlauben */
- }
-
-
-
-
-
- /**************************************************************************\
- * *
- * "initialize head" *
- * *
- * Listenkopf, auf den hd zeigt, initialisieren : *
- * *
- * *
- * +----------------------+ *
- * | +------------------+ | *
- * | | | | *
- * +--------+ v v +--------+ | | *
- * hd --->| | -> hd ------->| |-----+ | *
- * +--------+ +--------+ | *
- * | | | |-------+ *
- * +--------+ +--------+ *
- * | | | | *
- * *
- \**************************************************************************/
-
- VOID inithd(hd)
- register LHEAD *hd;
-
- {
- hd->head = hd->tail = hd;
- }
-
-
-
-
-
- /**************************************************************************\
- * *
- * "level 2 to level x" *
- * *
- * Meldung msg (L2M...) an Layer 3 und hoehere Layer weitergeben. *
- * *
- \**************************************************************************/
-
- VOID l2tolx(msg)
- register unsigned msg;
-
- {
- l2tol3(msg); /* Layer 2 -> Layer 3 */
- l2tol7(msg,lnkpoi,2); /* Layer 2 -> Layer 7 */
- }
-
- /* Ende von L2C.C */